#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys, thread, os, random, time
import Ice, IceStorm

try:
    HOME = os.environ['ROBOTS']
except KeyError:
    print 'ROBOTS environment variable is not currently defined.'
    sys.exit(0)

SLICE = os.path.join(HOME, 'slice')
FILE = os.path.join(SLICE, 'Robots.ice')
Ice.loadSlice('--all -I/usr/share/slice', ['-I' + SLICE, FILE])

KB = os.path.join(HOME, 'kb', 'Robots.xml')

import Robots
import Util
import Fuzzy
from Fuzzy import *

class AgentI (Robots.Agent):

    def __init__ (self, name, team, robot, adapter):
        # Agent's identity.
        self.__name = name
        self.__team = team

        # Robot's proxy.
        self.__robot = robot
        self.__goal = None

        # Load the fuzzy system.
        util = UtilFuzzy()
        util.loadFile(KB)
        self.__fuzzy = FuzzySystem(util.getSystemName())
        # Variables.
        for x in util.getVariables():
            self.__fuzzy.insertVar(x)
        # Rules.
        for i in range(len(util.getAntecedents())):
            self.__fuzzy.insertRule(util.getAntecedents()[i], util.getConsequences()[i])

        # Position.
        # TODO: get from the camera.
        #self.__currPos = Robots.Vec2(float(random.Random().randint(0, 120)), float(random.Random().randint(0, 170)))
        self.__goalPos = None

        self.__proxies = {}
        self.__destroyed = False
        self.__mutex = thread.allocate_lock()

        self.__proxies['self'] = Robots.AgentPrx.uncheckedCast(
            adapter.createProxy(self.__name))

        # Reference to the topic manager.
        try:
            #base = adapter.getCommunicator().stringToProxy('Robots.IceStorm/TopicManager')
            # TOCHANGE
            base = adapter.getCommunicator().stringToProxy('Robots/TopicManager:default -p 10000')
            self.__proxies['topicManager'] = IceStorm.TopicManagerPrx.checkedCast(base)
        except Ice.Exception, ex:
            sys.stdout.write('Invalid TopicManager: ' + str(ex))
            raise Ice.Exception

        # Team channel.
        try:
            self.__proxies[self.__team] = self.__proxies['topicManager'].retrieve(self.__team);
            #print 'Topic ' + self.__team + ' retrieved!'
        except IceStorm.NoSuchTopic:
            self.__proxies[self.__team] = self.__proxies['topicManager'].create(self.__team)
            #print 'Topic ' + self.__team + ' created!'

        # Subscription to the team event channel.
        try:
            qos = {}
            qos['reliability'] = 'ordered'
            self.__proxies['pub'] = Robots.AgentPrx.uncheckedCast(
                self.__proxies[self.__team].subscribeAndGetPublisher(qos, self.__proxies['self']).ice_oneway())
            print str(self.__proxies['self'].ice_getIdentity().name) + ' subscribed with the ' + self.__team + ' channel.'
        except IceStorm.AlreadySubscribed, ex:
            self.__proxies['pub'] = Robots.AgentPrx.uncheckedCast(
                self.__proxies[self.__team].getPublisher().ice_oneway())

    def setGoal (self, goal, curr):
        self.__goal = goal

        if isinstance(goal, Robots.SpreadGoal):            
            #print 'Goal is to spread around (' + str(goal.pos.x) + ', ' + str(goal.pos.y) + ')'
            self.__currPos = Robots.Vec2(random.Random().randint(0, 120), random.Random().randint(0, 170))

            # Calculate target positions.
            # Get the number of team members.
            team = Robots.AgentTeamPrx.uncheckedCast(
                curr.adapter.getCommunicator().stringToProxy(self.__team))
            #nAgents = len(team.list())
            # TOCHANGE
            nAgents = 4

            self.__positions = {}
            self.__mobility = {}
            # Calculate positions and mobility to each position.
            Util.mobility(self.__currPos, self.__goal, nAgents, self.__positions, self.__mobility, self.__fuzzy)

            # Get the closest position to the object.
            try:
                self.__goalPos = self.__positions[Util.closestPointToSpreadObject(self.__mobility)]
            except KeyError, ex:
                print ex
                return 

            print curr.id.name + ': current goal [' + str(self.__goalPos.x) + ', ' + str(self.__goalPos.y) + ']'
            # Publish its intentions.
            m = Robots.Message(self.__proxies['self'], 
                               Robots.RobotPosition(self.__goalPos, 0.0), 
                               self.__mobility[Util.getDictKeyFromValue(self.__positions, self.__goalPos)])

            time.sleep(float(random.Random().randint(50, 250)) / 100.0)
            self.__proxies['pub'].adv(m)

    def adv (self, m, curr):

        if self.__goalPos.x == m.rp.pos.x and self.__goalPos.y == m.rp.pos.y and self.__proxies['self'] != m.r:            

            # P2P auction.
            myMob = self.__mobility[Util.getDictKeyFromValue(self.__positions, self.__goalPos)]            

            if myMob < m.mob:        
                self.__mutex.acquire()
                #print curr.id.name + ': mobility to [' + str(self.__goalPos.x) + ', ' + str(self.__goalPos.y) + '] is: ' + str(myMob)
                #print curr.id.name + ': ' + str(myMob) + ' is lower than ' + Util.getProxyName(m.r) + "'s mobility: " + str(m.mob)
                # Somebody has a higher mobility.
                k = Util.removeValueFromDict(self.__positions, self.__goalPos)
                self.__mobility.pop(k)
                # Get the closest position to the object.
                try:
                    self.__goalPos = self.__positions[Util.closestPointToSpreadObject(self.__mobility)]
                except KeyError, ex:
                    print curr.id.name + ' is LOST.'
                    return 

                # Publish its intentions.
                msg = Robots.Message(self.__proxies['self'], 
                                     Robots.RobotPosition(self.__goalPos, 0.0), 
                                     self.__mobility[Util.getDictKeyFromValue(self.__positions, self.__goalPos)])
                                      
                self.__mutex.release()
                time.sleep(float(random.Random().randint(50, 250)) / 100.0)
                self.__proxies['pub'].adv(m)

                print curr.id.name + ': current goal [' + str(self.__goalPos.x) + ', ' + str(self.__goalPos.y) + ']'

    def destroy (self, curr):
        self.__mutex.acquire()
        if self.__destroyed:
            raise Ice.ObjectNotExistException
        self.__destroyed = True

        # Unsubscribe with the eventChannel.
        self.__proxies['team'].unsubscribe(self.__proxies['self'])

        # Remove the servant from the object adapter.
        curr.adapter.remove(curr.id)
        self.__mutex.release()

    def isZombie (self):
        return self.__destroyed
